import { defineComponent, ref, watch, provide, createVNode } from 'vue';
import VirtualList from '../virtual-list/index.js';
import Node from './Node.js';
import { TreeStore } from './store.js';
export { TreeCheckMod } from './store.js';
import Dropdown from '../Dropdown/index.js';

let dragHoverPartEnum = /*#__PURE__*/function (dragHoverPartEnum) {
  dragHoverPartEnum["before"] = "before";
  dragHoverPartEnum["body"] = "body";
  dragHoverPartEnum["after"] = "after";
  return dragHoverPartEnum;
}({});
const TreeContextKey = Symbol('TreeContextKey');
const Tree = /* @__PURE__ */ defineComponent({
  name: 'Tree',
  props: {
    emptyText: {
      type: String,
      default: '暂无数据'
    },
    data: {
      type: Array,
      default: () => []
    },
    checkable: {
      type: Boolean,
      default: false
    },
    checkRelation: {
      type: String,
      default: 'related'
    },
    directory: {
      type: Boolean,
      default: false
    },
    contextMenu: {
      type: Object
    },
    draggable: {
      type: Boolean,
      default: false
    },
    loadData: {
      type: Function
    },
    beforeDropMethod: {
      type: Function
    },
    beforeExpand: {
      type: Function
    },
    onNodeDragStart: {
      type: Function
    },
    onNodeDragEnter: {
      type: Function
    },
    onNodeDragOver: {
      type: Function
    },
    onNodeDragLeave: {
      type: Function
    },
    onSelectMenu: {
      type: Function
    },
    onChange: {
      type: Function
    },
    onContextMenu: {
      type: Function
    },
    selected: {
      type: [String, Number]
    },
    modelValue: {
      type: Array
    },
    keyField: {
      type: String
    },
    titleField: {
      type: String
    },
    selectedClass: {
      type: String
    },
    draggingClass: {
      type: String
    },
    customIcon: {
      type: Function
    },
    arrowIcon: {
      type: Function
    },
    mode: {
      type: String
    }
  },
  emits: ['nodeSelect', 'nodeExpand', 'nodeCollapse', 'nodeChecked', 'change', 'update:modelValue', 'update:selected', 'nodeDrop'],
  setup(props, {
    emit,
    expose
  }) {
    const vir = ref();
    const visible = ref(false);
    const x = ref(0);
    const y = ref(0);
    const emptyText = props.emptyText ?? '暂无数据';
    const treeStore = new TreeStore(props, emit);
    const store = treeStore.getStore();
    watch(() => props.data, () => {
      treeStore.init(props.data);
    }, {
      immediate: true
    });
    const onNodeCheck = (node, checked) => {
      treeStore.checkNode(node, checked);
      emit('nodeChecked', node, checked);
    };
    const onNodeExpandCollapse = async node => {
      const valid = props.beforeExpand ? await props.beforeExpand(node, !node.expand) : true;
      if (!valid) {
        return;
      }
      if (node.loading && props.loadData) {
        await treeStore.loadData(node, props.loadData);
      }
      treeStore.expandNode(node, !node.expand);
    };
    expose({
      prepend: treeStore.prepend,
      append: treeStore.append,
      insertBefore: treeStore.insertBefore,
      insertAfter: treeStore.insertAfter,
      getNode: treeStore.getNode,
      remove: treeStore.remove,
      filter: treeStore.filter,
      expandAll: treeStore.expandAll,
      collapseAll: treeStore.collapseAll,
      expandNode: async (nodeId, expand) => {
        const node = treeStore._getNode(nodeId);
        if (!node) return;
        if (node.expand !== expand) {
          onNodeExpandCollapse(node);
        }
      },
      scrollTo: (nodeId, position = 'top') => {
        const index = treeStore.getNodeIndexInShow(nodeId);
        const nodeHeight = 22;
        let top = index * nodeHeight;
        console.log(vir.value);
        if (position === 'center') {
          top = top - vir.value.$el.getBoundingClientRect().height / 2 + nodeHeight / 2;
        }
        if (position === 'bottom') {
          top = top - vir.value.$el.getBoundingClientRect().height + nodeHeight;
        }
        vir.value.$el.scrollTo({
          top,
          behavior: 'smooth'
        });
      },
      rename: treeStore.rename,
      checkNode: onNodeCheck,
      checkAll: treeStore.checkAll,
      uncheckAll: treeStore.uncheckAll,
      loadData: (nodeId, loadDataMethod) => {
        const node = treeStore._getNode(nodeId);
        if (!node) return;
        treeStore.loadData(node, loadDataMethod);
      },
      selectNode: treeStore.selectNode,
      getChecked: treeStore.getChecked,
      getCheckedKeys: treeStore.getCheckedKeys
    });
    const handleDrop = async (e, targetKey, hoverPart) => {
      if (e.dataTransfer) {
        try {
          const node = treeStore._getNode(targetKey);
          const dragNodeKey = e.dataTransfer.getData('node');
          const dragNode = treeStore._getNode(dragNodeKey);
          const shouldDrop = props.beforeDropMethod ? await props.beforeDropMethod(node, dragNode, hoverPart) : true;
          if (shouldDrop) {
            if (targetKey === dragNodeKey) return;
            if (hoverPart === dragHoverPartEnum.before) {
              treeStore.insertBefore(targetKey, dragNodeKey);
              // 如果是拖拽到父节点，并且父节点是展开的，则不管 hoverPart 是不是 after 都拖入为子节点
            } else if (hoverPart === dragHoverPartEnum.body || node.expand) {
              treeStore.prepend(targetKey, dragNodeKey);
            } else if (hoverPart === dragHoverPartEnum.after) {
              treeStore.insertAfter(targetKey, dragNodeKey);
            }
            emit('nodeDrop', e, node, dragNode, hoverPart);
          }
        } catch (err) {
          throw new Error(err);
        }
      }
    };
    provide(TreeContextKey, {
      onOpenClose: onNodeExpandCollapse,
      onNodeSelect: treeStore.selectNode,
      store: treeStore,
      draggable: props.draggable,
      checkable: props.checkable || false,
      onDrop: handleDrop,
      directory: props.directory,
      onContextMenu: props.onContextMenu,
      contextMenu: props.contextMenu,
      onNodeCheck: onNodeCheck,
      onDragStart: props.onNodeDragStart,
      onDragEnter: props.onNodeDragEnter,
      onDragLeave: props.onNodeDragLeave,
      onDragOver: props.onNodeDragOver,
      selectedClass: props.selectedClass,
      dragHoverClass: props.dragHoverClass,
      draggingClass: props.draggingClass,
      customIcon: props.customIcon,
      arrowIcon: props.arrowIcon
    });
    return () => props.contextMenu ? props.data && props.data.length ? createVNode(Dropdown, {
      "modelValue": visible.value,
      "onUpdate:modelValue": $event => visible.value = $event,
      "transfer": true,
      "trigger": "contextMenu",
      "position": {
        x: x.value,
        y: y.value
      },
      "onMouseClick": e => {
        x.value = e.pageX;
        y.value = e.pageY + 5;
      },
      "handler": ".cm-tree-text",
      "align": "bottomLeft",
      "menu": props.contextMenu,
      "onSelect": props.onSelectMenu
    }, {
      default: () => [createVNode("div", {
        "class": "cm-tree"
      }, [createVNode(VirtualList, {
        "onScroll": () => visible.value = false,
        "ref": vir,
        "items": store.nodeList,
        "itemEstimatedSize": 22
      }, {
        default: scope => {
          return createVNode(Node, {
            "data": scope.item
          }, null);
        }
      })])]
    }) : createVNode("div", {
      "class": "cm-tree-empty"
    }, [emptyText]) : createVNode("div", {
      "class": "cm-tree"
    }, [props.data && props.data.length ? createVNode(VirtualList, {
      "ref": vir,
      "items": store.nodeList,
      "itemEstimatedSize": 22
    }, {
      default: scope => {
        return createVNode(Node, {
          "key": scope.item.id,
          "data": scope.item
        }, null);
      }
    }) : createVNode("div", {
      "class": "cm-tree-empty"
    }, [emptyText])]);
  }
});

export { TreeContextKey, TreeStore, Tree as default, dragHoverPartEnum };
